/*
 * Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.cloudphone.common;

public class CasRemoteMessage {
    public static final int MSG_SET = 0;
    public static final int MSG_START = 1;
    public static final int MSG_READ = 2;
    public static final int MSG_WRITE = 3;
    public static final int MSG_STOP = 4;
    public static final int MSG_DESTRUCT = 5;
    public static final int MSG_SETVOLUME = 6;
    public static final int MSG_USE_URL = 7;
    public static final int SIZEOFINT = 4;
    public static final int SIZEOFLONG = 8;
    public static final int SIZEOFFLOAT = 4;
    public static final int SIZEOFSHORT = 2;
    private byte[] mBuffer;
    private int mReadPosition = 0;
    private int mWritePosition = 0;

    public CasRemoteMessage(int size) {
        mBuffer = new byte[size];
    }

    public CasRemoteMessage(byte[] buffer) {
        mBuffer = new byte[buffer.length];
        System.arraycopy(buffer, 0, mBuffer, 0, buffer.length);
    }

    public CasRemoteMessage(byte[] buffer, int start, int size) {
        if (start + size > buffer.length) {
            size = buffer.length - start;
        }
        mBuffer = new byte[size];
        System.arraycopy(buffer, start, mBuffer, 0, size);
    }

    private static int bytesToInt(byte[] b) {
        return (b[3] & 0xFF)
            | (b[2] & 0xFF) << 8
            | (b[1] & 0xFF) << 16
            | (b[0] & 0xFF) << 24;
    }

    private static float bytesToFloat(byte[] b) {
        int intbits = bytesToInt(b);
        return Float.intBitsToFloat(intbits);
    }

    private static short byteToShort(byte[] b) {
        return (short) ((b[1] << 8) | b[0] & 0xff);
    }

    private static byte[] intToBytes(int a) {
        return new byte[] {
            (byte) ((a >> 24) & 0xFF),
            (byte) ((a >> 16) & 0xFF),
            (byte) ((a >> 8) & 0xFF),
            (byte) (a & 0xff)
        };
    }

    private static byte[] longToBytes(long a) {
        return new byte[] {
            (byte) ((a >> 56) & 0xFF),
            (byte) ((a >> 48) & 0xFF),
            (byte) ((a >> 40) & 0xFF),
            (byte) ((a >> 32) & 0xFF),
            (byte) ((a >> 24) & 0xFF),
            (byte) ((a >> 16) & 0xFF),
            (byte) ((a >> 8) & 0xFF),
            (byte) (a & 0xff)
        };
    }

    private static byte[] floatToBytes(float a) {
        int intbits = Float.floatToIntBits(a);
        return intToBytes(intbits);
    }

    /**
     * 从字节数组(mBuffer)的当前读取位置(mReadPosition)开始读取一个int长度(4字节)的数据
     *
     * @return
     */
    public int readInt() {
        byte[] bytes = new byte[SIZEOFINT];
        System.arraycopy(mBuffer, mReadPosition, bytes, 0, SIZEOFINT);
        mReadPosition += SIZEOFINT;
        return bytesToInt(bytes);
    }

    /**
     * 从字节数组(mBuffer)的当前读取位置(mReadPosition)开始读取一个short长度(2字节)的数据
     *
     * @return
     */
    public short readShort() {
        byte[] bytes = new byte[SIZEOFSHORT];
        System.arraycopy(mBuffer, mReadPosition, bytes, 0, SIZEOFSHORT);
        mReadPosition += SIZEOFSHORT;
        return byteToShort(bytes);
    }

    public long readLong() {
        long high = readInt();
        long low = readInt();
        long l = 0;

        l = l | high;
        l = l << 32;
        /* note the below 0x00000000ffffffffL is important */
        l = l | (low & 0x00000000ffffffffL);

        return l;
    }

    public byte[] readBytes(int size) {
        byte[] bytes = new byte[size];
        System.arraycopy(mBuffer, mReadPosition, bytes, 0, size);
        mReadPosition += size;
        return bytes;
    }

    public float readFloat() {
        byte[] bytes = new byte[SIZEOFFLOAT];
        System.arraycopy(mBuffer, mReadPosition, bytes, 0, SIZEOFFLOAT);
        mReadPosition += SIZEOFFLOAT;
        return bytesToFloat(bytes);
    }

    public void writeInt(int value) {
        System.arraycopy(intToBytes(value), 0, mBuffer, mWritePosition, SIZEOFINT);
        mWritePosition += SIZEOFINT;
    }

    public void writeLong(int value) {
        System.arraycopy(longToBytes(value), 0, mBuffer, mWritePosition, SIZEOFLONG);
        mWritePosition += SIZEOFLONG;
    }

    public void writeBytes(byte[] bytes) {
        System.arraycopy(bytes, 0, mBuffer, mWritePosition, bytes.length);
        mWritePosition += bytes.length;
    }

    public void writeFloat(float value) {
        System.arraycopy(floatToBytes(value), 0, mBuffer, mWritePosition, SIZEOFFLOAT);
        mWritePosition += SIZEOFFLOAT;
    }

    public byte[] getBuffer() {
        return mBuffer;
    }

    public int getSize() {
        return mBuffer.length;
    }
}
